package com.soup.bytebuddy;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.pool.TypePool;
import org.hamcrest.Matcher;
import org.junit.Assert;
import org.junit.Test;

import java.lang.reflect.Field;
import java.util.concurrent.ThreadPoolExecutor;

import static org.junit.Assert.assertThat;

/**
 * 〈一句话功能简述〉<br>
 *
 *     <a href='https://vimsky.com/examples/detail/java-class-net.bytebuddy.ByteBuddy.html'></a>
 *
 *     <a href='https://github.com/raphw/byte-buddy/'>byte-buddy</a>
 *
 *     https://blog.gmem.cc/byte-buddy-study-note
 *
 * @author zhaoyi
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
public class BytebuddyTester {

    /**
     * 创建新类型
     * @throws Exception
     */
    @Test
    public void simpleTest() throws Exception {
        Class<?> dynamicType = new ByteBuddy()
                // 指定父类
                .subclass(Object.class)
                // 根据名称来匹配需要拦截的方法
                .method(ElementMatchers.named("toString"))
                // 拦截方法调用，返回固定值
                .intercept(FixedValue.value("Hello World!"))
                // 产生字节码
                .make()
                // 加载类
                .load(getClass().getClassLoader())
                // 获得Class对象
                .getLoaded();

        // System.out.println(dynamicType.newInstance().toString());

        Assert.assertEquals(dynamicType.newInstance().toString(), "Hello World!");

        // assertThat(dynamicType.newInstance().toString(), is("Hello World!"));
    }

    /**
     * 操作未加载的类
     */
    @Test
    public void operationUnloadClass() throws Exception {
        // 在TypePool中维护类型的元数据TypeDescription
        /*TypePool typePool = TypePool.Default.ofClassPath();

        new ByteBuddy()
                .redefine(typePool.describe("java.util.concurrent.ThreadPoolExecutor").resolve(), // 根据名称进行解析类
                        // ClassFileLocator用于定位到被修改类的.class文件
                        ClassFileLocator.ForClassLoader.ofClassPath())
                .defineField("testInjectField", String.class)
                .make()
                .load(ClassLoader.getSystemClassLoader());
        Field field = ThreadPoolExecutor.class.getDeclaredField("testInjectField");
        System.out.println(field.getType());*/
    }

}
